#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "StdTcp.h"
#include "StdThread.h"
#include "../GlobalMessage.h"
#include "DoubleLinkList.h"
#include "DataCenter.h"
#include "StdThreadPool.h"
#include "FileSystem.h"
#include "ServerFunc.h"

#define ip "172.29.0.125"
#define port 8082

DLlist ClientList; //在线用户列表
FileSys *fs;    //文件系统

// 获取在线列表 将列表中所有在线用户填入字符串中并返回申请的空间中，以‘,’分隔
char* GetOnlinelist()
{
    char* content = (char*)malloc(ContentSize);
    if(content == NULL)
    {
        printf("GetOnlinelist malloc error!\n");
        exit(-1);
    }
    memset(content,0,ContentSize);
    DLNode *travelPoint = ClientList.head->next;
    while(travelPoint != NULL)
    {
        CInfo *c = (CInfo*)travelPoint->data;
        strcat(content,c->ClientName);
        strcat(content,",");
        travelPoint = travelPoint->next;
    }
    content[strlen(content) - 1] = '\0';
    return content;
}

//文件传输给客户端  消息内容:文件路径
void SendFileToClient(MSG *m,int clientsock)
{
    char *fileName = GetFileNameFromPath(m->Content);
    if (fileName == NULL) 
    {
        printf("错误: 无法从路径中获取文件名\n");
        return;
    }
    PackFile *pf = PacketFileInit(m->Content);//获取文件描述符和大小
    memset(m->Content,0,sizeof(m->Content));


    strcpy(m->Content + 4,fileName);
    int size = 1000;//默认为1000 不足在函数中自动更新
    int count = 0;
    while(IsFileEnd(pf) == false)
    {
        //读取的文件数据大小会放在size中
        ReadFromFile(pf,m->Content + 24,&size);
        //填入读取的文件内容大小
        memcpy(m->Content,&size,sizeof(int)); 
        TcpServerSend(clientsock,m,sizeof(MSG));//TcpserSend(c,m,sizeof(MSG));
        count++;
        printf("msg flag : %d   这是第%d包数据,大小:%d\n",m->flag,count,size);
    }

    //传结束的空包 
    size = -1;
    memcpy(m->Content,&size,sizeof(int));
    TcpServerSend(clientsock,m,sizeof(MSG));//

    free(fileName);// 释放
    ClearPacketFile(pf);
}

// 处理客户端发送消息并处理需求
void SolveRequest(MSG *m,int clientSock)
{
    switch(m->flag)
    {
        //注册
        case SIGNUP:
            //当前用户名未被注册
            if(IsUserExist(m->FromName) == false)
            {
                if(AddNewUser(m->FromName,m->Content) == true)
                {
                    InsertDLlistTial(&ClientList,CreateCInfo(m->FromName,clientSock));
                    TravelDLlist(&ClientList,PrintCInfo);
                    memset(m->Content,ContentSize,0);
                    strcpy(m->Content,"注册成功");
                    CreateNewDirInFs(fs,m->FromName);// 创建新用户自己的文件夹
                }
                else
                {
                    memset(m->Content,ContentSize,0);
                    strcpy(m->Content,"服务器错误");
                }
            }
            //用户名已被注册
            else
            {
                memset(m->Content,ContentSize,0);
                strcpy(m->Content,"用户名已被注册");
            }
            TcpServerSend(clientSock,m,sizeof(MSG));
            break;
        //登录
        case LOGIN:
            //账号是否存在
            if(IsUserExist(m->FromName) == true)
            {
                if(IsAccountEqual(m->FromName,m->Content) == true)
                {
                    InsertDLlistTial(&ClientList,CreateCInfo(m->FromName,clientSock));
                    TravelDLlist(&ClientList,PrintCInfo);
                    memset(m->Content,ContentSize,0);
                    strcpy(m->Content,"登录成功");
                }
                else
                {
                    memset(m->Content,ContentSize,0);
                    strcpy(m->Content,"账号密码错误");
                }
            }
            else
            {
                memset(m->Content,ContentSize,0);
                strcpy(m->Content,"账号不存在");
            }
            TcpServerSend(clientSock,m,sizeof(MSG));
            break;
        case CHAT:     // 发送消息给目标用户
        // {
            
        //     DLlist findList = FindByElement(&ClientList, m->ToName, IsClientNameEqual);
        //     if (findList.len == 0) // 离线
        //     {
        //         AddChatHistory(m->FromName, m->ToName, m->Content);
        //         char *result = (char *)malloc(ContentSize);
        //         memset(result, 0, ContentSize);
        //         result = GetChatHiostory(m->FromName, m->ToName);
        //         printf("result:%s\n", result);
        //         memset(m->Content, 0, ContentSize);
        //         strcpy(m->Content, result);
        //         TcpServerSend(clientSock, m, sizeof(MSG));
        //         free(result);
        //     }
        //     else
        //     {
        //         AddChatHistory(m->FromName, m->ToName, m->Content);
        //         CInfo *c = (CInfo *)findList.head->next->data;
        //         printf("准备给|%s||套接字：%d|的用户发送消息\n", c->ClientName, c->sock);
        //         char *result = (char *)malloc(ContentSize);
        //         memset(result, 0, ContentSize);
        //         result = GetChatHiostory(m->FromName, m->ToName);
        //         printf("result:%s\n", result);
        //         memset(m->Content, 0, ContentSize);
        //         strcpy(m->Content, result);
        //         free(result);
        //         TcpServerSend(c->sock, m, sizeof(MSG));
        //         TcpServerSend(clientSock, m, sizeof(MSG));
        //         printf("content:%s", m->Content);
        //         ClearDLlist(&findList, NULL);
        //     }
        //     break;
        // }
        case SENDFILE: // 与私聊逻辑一致...都涉及将消息或文件发送给目标用户
            DLlist  findList = FindByElement(&ClientList,m->ToName,IsClientNameEqual);//查找目标用户
            if(findList.len == 0)
            {
                printf("没有找到名称为|%s|的用户\n",m->ToName);
            }
            else
            {
                CInfo *c = (CInfo*)findList.head->next->data;
                printf("准备给|%s||套接字:%d|的用户发消息\n",c->ClientName,c->sock);
                TcpServerSend(c->sock,m,sizeof(MSG));
            }
            ClearDLlist(&findList,NULL);
            break;
        case BROADCAST:
            DLNode *travelPoint = ClientList.head->next;
            while(travelPoint != NULL)
            {
                CInfo *c = (CInfo*)travelPoint->data;
                if(strcmp(c->ClientName,m->FromName) != 0)
                {
                    TcpServerSend(c->sock,m,sizeof(MSG));
                }
                travelPoint = travelPoint->next;
            }
            break;
        case ONLINELIST:
        {
            char *content = GetOnlinelist();
            printf("在线列表为:%s\n",content);
            strcpy(m->Content,content);
            TcpServerSend(clientSock,m,sizeof(MSG));
            free(content);
            break;
        }
        case UPLOAD:// 服务器: 接收并解析上传的文件
        {
            int size = 0;
            memcpy(&size,m->Content,4);// 填四个字节
            if (size == -1)
            {
                memset(m->Content, 0, sizeof(m->Content));
                strcpy(m->Content,"UPDATEOK");
                TcpServerSend(clientSock, m, sizeof(MSG));
                break;
            }
            char fileName[NameSize] = {0};
            strcpy(fileName, m->Content + 4);// 字符串是文件名: 从第四个开始，总共是20个
            WriteFileToFs(fs, m->FromName, fileName, m->Content + 24, size);
            break;
        }
        case FILELIST:// 获取文件列表
        {
            char *list = GetFileList(fs, m->FromName);
            if (list == NULL)
            {
                memset(m->Content, 0, sizeof(m->Content));
                strcpy(m->Content, "FILELISTERROR");
            }
            else
            {
                memset(m->Content, 0, sizeof(m->Content));
                strcpy(m->Content, list);
                free(list);
            }
            TcpServerSend(clientSock, m, sizeof(MSG));// 发送给客户端
            break;
        }
        case DOWNLOAD:// 下载文件
        {
            char *filepath = GetServerFileDirPath(fs,m->FromName,m->Content);//获取文件路径
            printf("获取的文件路径：%s",filepath);

            memset(m->Content,0,sizeof(m->Content));
            strcpy(m->Content,filepath);
            SendFileToClient(m,clientSock);
            free(filepath);
            break;
        }
        case ADDFRIEND:// 添加好友
        {
            if (AddFriend(m->FromName, m->ToName) == false)
            {
                strcpy(m->Content, "notexist");
                TcpServerSend(clientSock, m, sizeof(MSG));
            }
            else
            {
                //将好友申请添加进入表中
                NewFriendApplication(m->FromName, m->ToName);
                DLlist findList = FindByElement(&ClientList, m->ToName, IsClientNameEqual);
                if (findList.len == 0)
                {
                    //用户不在线 添加消息进入未读消息表
                    memset(m->Content,0,sizeof(m->Content)); 
                    strcpy(m->Content,"该用户还未上线!");
                    ClearDLlist(&findList,NULL);
                    TcpServerSend(clientSock,m,sizeof(MSG));
                    break;
                }
                else
                {
                    // 用户在线 发送好友申请
                    memset(m->Content,0,sizeof(m->Content)); 
                    strcpy(m->Content,"您有新的好友申请\n");
                    // 第一个实际数据节点
                    CInfo *c = (CInfo *)findList.head->next->data;
                    printf("准备给|%s||套接字：%d|的用户发消息\n",c->ClientName,c->sock);
                    TcpServerSend(c->sock,m,sizeof(MSG));
                    ClearDLlist(&findList,NULL);
                }
                
            }
            break;
        }
        case MYFRIENDLIST:// 获取好友列表
        {
            char *friends = FriendCollect(m->FromName);
            printf("查找到的好友列表为：%s\n",friends);
            strcpy(m->Content,friends);
            //接受到好友列表的请求 将好友添加到字符串 发送给客户端
            free(friends);
            TcpServerSend(clientSock,m,sizeof(MSG));
            break;
        }
        case DELETEFRIEND:// 删除好友
        {
            //删除好友 1 查看该用户是否在好友列表中 2 如果在就将列表中删除
            if (IsFriendExist(m->FromName,m->Content) == true)
            {
                DeleteFriend(m->FromName,m->Content);
                memset(m->Content,0,sizeof(m->Content));
                strcpy(m->Content,"好友已经被删除");
            }
            else
            {
                memset(m->Content,0,sizeof(m->Content));
                strcpy(m->Content,"好友不存在");
            }
            TcpServerSend(clientSock,m,sizeof(MSG));
            break;
        }
        case FRIENDCHAT:// 好友聊天
        {
            // 先判断用户是否存在
            if (IsUserExist(m->ToName) == false)
            {
                strcpy(m->Content + 50,"该用户不存在");
                TcpServerSend(clientSock,m,sizeof(MSG));
                break;
            }
            // 在判断用户是否为好友
            if (IsFriendExist(m->ToName,m->FromName) == false)
            {
                strcpy(m->Content + 50,"该用户还未成为你的好友");
                TcpServerSend(clientSock,m,sizeof(MSG));
                break;
            }
            AddInsertMessages(m);
            // 最后用户是否在线
            DLlist findList = FindByElement(&ClientList,m->ToName,IsClientNameEqual);
            if (findList.len == 0)
            {
                ClearDLlist(&findList,NULL);
                TcpServerSend(clientSock,m,sizeof(MSG));
                printf("用户不在线\n");
                break;
            }
            else
            {
                CInfo *c = (CInfo *)findList.head->next->data;
                printf("准备给|%s||套接字：%d|的用户发消息\n",c->ClientName,c->sock);
                TcpServerSend(c->sock,m,sizeof(MSG));//用户在线发送给接收者
                TcpServerSend(clientSock,m,sizeof(MSG));//发送给发送者
                ClearDLlist(&findList,NULL);
            }
            break;

        }
        // //在数据库中查找添加好友toname为fromname的用户名
        case MYFRIENDREQUEST:
        {
            char *application=SearchFriendApplication(m->FromName);
            strcpy(m->Content,application);
            free(application);
            TcpServerSend(clientSock,m,sizeof(MSG));
            break;
        }
        case CALLFRIENDREQUEST:
        {
            if (IsUserExist(m->ToName) == false)
            {
                strcpy(m->Content,"您输入的用户不存在");
                TcpServerSend(clientSock,m,sizeof(MSG));
            }
            else
            {
                AddFriend(m->FromName,m->ToName);//用户存在
                DeleteFriendApplication(m->ToName,m->FromName);
                strcpy(m->Content,"成功添加好友");
                TcpServerSend(clientSock,m,sizeof(MSG));
            }
            break;
        }

        case CREATEGROUP:// 创建群组
        {
            // 判断是否已经存在群组
            if (IsExistsGroup(m->Content) == true)
            {
                memset(m->Content,0,sizeof(m->Content));
                strcpy(m->Content,"该群已经存在，请重新选择新的群名称。");
                TcpServerSend(clientSock,m,sizeof(MSG));
            }
            else
            {
                ServerCreateGroup(m->Content,m->FromName);// 创建群
                InserintoGroupMembers(m->Content,m->FromName,1);
                memset(m->Content,0,sizeof(m->Content));
                strcpy(m->Content,"创建成功");
                TcpServerSend(clientSock,m,sizeof(MSG));
            }
            break;
        }
        case VISITWHOJOINGROUP://添加群成员
        {
            // 先判断用户是否在列表中
            if (IsUserExist(m->ToName) == false)
            {
                memset(m->Content,0,sizeof(m->Content));
                strcpy(m->Content,"该用户不存在。");
                TcpServerSend(clientSock,m,sizeof(MSG));
                break;
            }
            // 判断用户是否为群管理者
            if (IsManageGroup(m->FromName,m->Content) == false)
            {
                memset(m->Content,0,sizeof(m->Content));
                strcpy(m->Content,"你还未成为该群组的管理者。");
                TcpServerSend(clientSock,m,sizeof(MSG));
                break;
            }
            // 判断用户是否已经在群中
            if (IsExistGroupMember(m->Content,m->ToName) == true)
            {
                memset(m->Content,0,sizeof(m->Content));
                strcpy(m->Content,"该用户已经在群中。");
                TcpServerSend(clientSock,m,sizeof(MSG));
                break;
            }
            //发起群组邀请
            InsertGroupInvite(m->FromName,m->ToName,m->Content);
            memset(m->Content,0,sizeof(m->Content));
            strcpy(m->Content,"成功发送该邀请。");
            TcpServerSend(clientSock,m,sizeof(MSG));
            break;
        }
        case INVITATIONJOINGROUPNOTIFICATION:// 邀请入群通知
        {
            // 查找邀请信息
            char *groupinvitelist = SearchGroupInvite(m->FromName);
            memset(m->Content,0,sizeof(m->Content));
            strcpy(m->Content,groupinvitelist);//将邀请信息复制到消息内容中
            free(groupinvitelist);
            TcpServerSend(clientSock,m,sizeof(MSG));
            break;
        }
        case PROCESSGROUPINVITATION:// 处理入群邀请
        {
            //接受到同意邀请的信息，群 被邀请者
            if (IsExistGroupInvition(m->Content,m->FromName) == false)
            {
                memset(m->Content,0,sizeof(m->Content));
                strcpy(m->Content,"信息错误");
            }
            else
            {
                //删除邀请表中的对应消息并添加群关系
                DeleteGroupInvite(m->FromName,m->Content);
                InserintoGroupMembers(m->Content,m->FromName,0);
                memset(m->Content,0,sizeof(m->Content));
                strcpy(m->Content,"加入成功");
            }
            TcpServerSend(clientSock,m,sizeof(MSG));
            break;
        }
        case GROUPMESSAGERECORD:// 群聊
        {
            // 判断发送者是否在目标群中
            if (IsExistGroupMember(m->ToName,m->FromName) == false)
            {
                // 如果发送者不在群组中，设置错误消息并发送给客户端
                strcpy(m->Content+50,"您尚未加入该群组");
                TcpServerSend(clientSock,m,sizeof(MSG));
                break;
            }
            AddInsertMessages(m);//将消息插入数据库中

            // 遍历客户端列表，向群组成员发送消息
            DLNode *travelPoint = ClientList.head->next;//第一个实际节点
            while (travelPoint != NULL)
            {
                CInfo *c =(CInfo*)travelPoint->data;
                // 如果在线用户不是自己并且在群组中，发送消息
                if ((strcmp(c->ClientName,m->FromName)!=0) && (IsExistGroupMember(m->ToName,c->ClientName)==true))//如果在线用户不是自己并且再群组中
                {
                    TcpServerSend(c->sock,m,sizeof(MSG));
                }
                // 下一个
                travelPoint = travelPoint->next;
            }
            TcpServerSend(clientSock,m,sizeof(MSG));
            break;
        }
        case MYGROUPLIST:// 我的群列表
        {
            char *groupnames = SearchGroups();//将返回的群组名称字符串赋值给 groupnames
            memset(m->Content,0,sizeof(m->Content));
            strcpy(m->Content,groupnames);
            TcpServerSend(clientSock,m,sizeof(MSG));
            free(groupnames);
            break;
        }
        case DELETEGROUP:// 删除群
        {
            //删除好友 1 查看该用户是否在群中 2 如果在就将群删除
            if (IsExistGroupMember(m->FromName,m->Content) == true)
            {
                DeleteGroup(m->FromName,m->Content);
                memset(m->Content,0,sizeof(m->Content));
                strcpy(m->Content,"该群已经被删除");
            }
            else
            {
                memset(m->Content,0,sizeof(m->Content));
                strcpy(m->Content,"群不存在");
            }
            TcpServerSend(clientSock,m,sizeof(MSG));
            break;
        }
        default:
            break;
    }
}


void *ClientHandle(void*arg)
{
    int clientSock = *((int*)arg);
    while (1)
    {
        MSG m;
        if(TcpServerRecv(clientSock,&m,sizeof(MSG)) == false)
        {
            printf("客户端|%d|已下线\n",clientSock);
            break;
        }
        // printf("收到来自客户端|%d|的消息:%s\n",clientSock,msg);
        SolveRequest(&m,clientSock);
    }

    //删除用户
    int* clientSockPtr = malloc(sizeof(int));
    if (clientSockPtr != NULL) 
    {
        *clientSockPtr = clientSock;
        RemoveByElement(&ClientList, (void*)clientSockPtr, IsClientSockEqual, free);
    } else 
    {
        // 处理内存分配失败的情况
    }
    return NULL;
}

int main()
{
    if(DataCenterInit() == false)
    {
        printf("数据中心初始化失败!\n");
        return -1;
    }
    InitDLlist(&ClientList);
    TcpS *s = TcpServerInit(ip,port);
    ThreadP *p = ThreadPoolInit(10,2,10,3600);
    fs = FileSystemInit("./filesystem");// 文件系统初始化

    int clientSock = -1;
    while((clientSock = TcpServerAccept(s)) >= 0)
    {
        printf("接入新的客户端，套接字是:%d\n",clientSock);
        ThreadPoolAddTask(p,ClientHandle,&clientSock);
    }
    return 0;
}